/**
 * 渲染器
 * @param {*} vnode 虚拟DOM对象
 * @param {*} container 容器，真实DOM，把渲染器把虚拟DOM挂载到真实DOM
 */
function renderer(vnode, container) {
  if (typeof vnode.tag === 'string') {
    // 标签元素
    mountElement(vnode, container)
  } else if (typeof vnode.tag === 'function') {
    // 组件
    mountComponent(vnode, container)
  } else if (typeof vnode.tag === 'object') {
    mountComponentObj(vnode, container)
  }
}

function mountElement(vnode, container) {
  // 使用vnode.tag作为标签名创建DOM元素
  const el = document.createElement(vnode.tag)
  // 遍历vnode.props,将属性、事件添加到DOM元素
  for (const key in vnode.props) {
    if (/^on/.test(key)) {
      // 如果以on开头，说明它是事件
      el.addEventListener(key.substr(2).toLowerCase(), vnode.props[key])
    }
  }

  // 处理children
  if (typeof vnode.children === 'string') {
    // 如果children是字符串，说明是文本子节点
    el.appendChild(document.createTextNode(vnode.children))
  } else if (Array.isArray(vnode.children)) {
    vnode.children.forEach(child => renderer(child, el))
  }
  container.appendChild(el)
}


function mountComponent(vnode, container) {
  // 调用组建函数，获取组件要渲染的内容（虚拟DOM）
  const subtree = vnode.tag()
  renderer(subtree, container)
}

function mountComponentObj(vnode, container) {
  const subtree = vnode.tag.render()
  renderer(subtree, container)
}


const vnode = {
  // 组件
  // tag: MyComponent,
  tag: MyComponentObj

  /**
    * tag: 标签名
    * props: 对象，表述div标签的属性、事假等内容
    * children：描述标签的子节点
 */
  // tag: 'div',
  // props: {
  //   onClick: () => alert('vue3')
  // },
  // children: 'click me'
}

// 虚拟DOM除了描述真实DOM外，还可以描述组件
// 组件就是一组DOM元素的封装,这组DOM元素就是组件要渲染的内容
// 定义一个函数代表组件，函数的返回值就是组件要渲染的内容
// 组件的返回值也是虚拟DOM，它代表组件要渲染的内容
const MyComponent = function () {
  return {
    tag: 'div',
    props: {
      onClick: () => alert('vue3')
    },
    children: 'click me'
  }
}

// 组件是个对象
const MyComponentObj = {
  render() {
    return {
      tag: 'div',
      props: {
        onClick: () => alert('vue3')
      },
      children: 'click me'
    }
  }
}

renderer(vnode, document.body)